package org.filecollector.filecontroller.basicsfilecontroller;

import junit.framework.TestCase;
import org.apache.commons.lang3.tuple.Pair;
import org.filecollector.filecontroller.operationresults.OperationResponse;
import org.filecollector.filecontroller.virtualcatalogue.VirtualCatalogue;
import org.filecollector.filecontroller.virtualcatalogue.VirtualCatalogueFactory;
import org.filecollector.filecontroller.virtualcatalogue.groupname.GroupName;
import org.filecollector.filecontroller.virtualcatalogue.groupname.GroupNameFactory;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestBasicsFileControllerSM {

    @Test
    public void testCreateEmpty() {
        Long id = 0L;
        var vc = VirtualCatalogueFactory.constructTest("07M60");
        TestCase.assertEquals(
                OperationResponse.constructSuccess(),
                BasicsFileControllerStaticMethods.createEmpty(
                        id,
                        (String _) -> {},
                        (String _) -> {},
                        (String _) -> {},
                        (Long a) -> a.equals(id),
                        (Long _) -> vc
                )
        );
        TestCase.assertTrue(vc.exists(id));
        TestCase.assertEquals(
                OperationResponse.constructWrongId(),
                BasicsFileControllerStaticMethods.createEmpty(
                        id,
                        (String _) -> {},
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> false,
                        (Long _) -> vc
                )
        );
        TestCase.assertEquals(
                OperationResponse.constructSomethingGoesWrong(),
                BasicsFileControllerStaticMethods.createEmpty(
                        9000000L,
                        (String _) -> {},
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> true,
                        (Long _) -> vc
                )
        );
    }

    @Test
    public void testCreateBuf() {
        var buffer = "FUCK";
        Long id = 0L;
        var vc = VirtualCatalogueFactory.constructTest("06M60");
        TestCase.assertEquals(
                OperationResponse.constructSuccess(),
                BasicsFileControllerStaticMethods.createBuf(
                        id,
                        buffer,
                        (String _) -> {},
                        (String _) -> {},
                        (String _) -> {},
                        (Long a) -> a.equals(id),
                        (Long _) -> vc
                )
        );
        TestCase.assertTrue(vc.exists(id));
        TestCase.assertEquals(buffer, String.valueOf(vc.readDirectly(id, buffer.length()).get()));
        TestCase.assertEquals(
                OperationResponse.constructWrongId(),
                BasicsFileControllerStaticMethods.createBuf(
                        id,
                        buffer,
                        (String _) -> {},
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> false,
                        (Long _) -> vc
                )
        );
        TestCase.assertEquals(
                OperationResponse.constructSomethingGoesWrong(),
                BasicsFileControllerStaticMethods.createBuf(
                        9000000L,
                        buffer,
                        (String _) -> {},
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> true,
                        (Long _) -> vc
                )
        );
    }

    @Test
    public void testCreateCatalogue() {
        String name = "0M60";
        var test = VirtualCatalogueFactory.constructTest(name);
        VirtualCatalogue[] list = new VirtualCatalogue[1];
        TestCase.assertEquals(
                OperationResponse.constructSuccess(),
                BasicsFileControllerStaticMethods.createCatalogue(
                        name,
                        (String _) -> {},
                        (String _) -> {},
                        () -> Optional.of(test),
                        (GroupName _) -> true,
                        (GroupName _) -> false,
                        (VirtualCatalogue vc) -> list[0] = vc
                )
        );
        TestCase.assertEquals(list[0], test);
        TestCase.assertEquals(
                OperationResponse.constructSomethingGoesWrong(),
                BasicsFileControllerStaticMethods.createCatalogue(
                        name,
                        (String _) -> {},
                        (String _) -> {},
                        Optional::empty,
                        (GroupName _) -> true,
                        (GroupName _) -> false,
                        (VirtualCatalogue _) -> {}
                )
        );
        TestCase.assertEquals(
                OperationResponse.constructCatalogueAlreadyTracking(),
                BasicsFileControllerStaticMethods.createCatalogue(
                        name,
                        (String _) -> {},
                        (String _) -> {},
                        () -> Optional.of(test),
                        (GroupName _) -> false,
                        (GroupName _) -> false,
                        (VirtualCatalogue _) -> {}
                )
        );
        TestCase.assertEquals(
                OperationResponse.constructWrongCatalogueName(),
                BasicsFileControllerStaticMethods.createCatalogue(
                        name,
                        (String _) -> {},
                        (String _) -> {},
                        () -> Optional.of(test),
                        (GroupName _) -> true,
                        (GroupName _) -> true,
                        (VirtualCatalogue _) -> {}
                )
        );
    }

    @Test
    public void testReadBuffer() {
        var buffer = "FUCK";
        Long id = 0L;
        var vc = VirtualCatalogueFactory.constructTest("05M60");
        vc.touch(id);
        vc.writeDirectly(id, buffer.toCharArray());
        TestCase.assertEquals(
                String.valueOf(OperationResponse.constructSuccessBuffered(buffer.toCharArray()).buffer().get()),
                String.valueOf(BasicsFileControllerStaticMethods.readBuf(
                        id,
                        buffer.length(),
                        (String _) -> {},
                        (String _) -> {},
                        (Long a) -> a.equals(id),
                        (Long _) -> vc
                ).buffer().get()
                )
        );
        TestCase.assertEquals(
                OperationResponse.constructWrongId(),
                BasicsFileControllerStaticMethods.readBuf(
                        id,
                        buffer.length(),
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> false,
                        (Long _) -> vc
                )
        );
    }

    @Test
    public void testReadAllIds(){
        int size = 100;
        var random = new Random(System.currentTimeMillis());
        var ids = new HashSet<Long>();
        var vc = VirtualCatalogueFactory.constructTest("04M60");
        for (int i = 0; i < size; i++) {
            Long id = Math.abs(random.nextLong()) % 100_000L;
            ids.add(id);
            vc.touch(id);
        }
        var expected = "{\"id\":[" + ids.stream()
                .map(a -> Long.toString(a, 16))
                .sorted()
                .collect(Collectors.joining(", ")) + "]}";
        var resp = String.valueOf(
                BasicsFileControllerStaticMethods.readAllIds(
                        (String _) -> {},
                        () -> Stream.of(vc)
                ).buffer().get()
        );
        TestCase.assertEquals(expected, resp);
    }

    @Test
    public void testReadIdGroup() {
        int size = 100;
        var random = new Random(System.currentTimeMillis());
        var ids = new HashSet<Long>();
        var vc = VirtualCatalogueFactory.constructTest("03M60");
        for (int i = 0; i < size; i++) {
            Long id = Math.abs(random.nextLong()) % 100_000L;
            ids.add(id);
            vc.touch(id);
        }
        var expected = "{\"id\":[" + ids.stream()
                .map(a -> Long.toString(a, 16))
                .sorted()
                .collect(Collectors.joining(", ")) + "]}";
        var resp = String.valueOf(
                BasicsFileControllerStaticMethods.readIdGroup(
                        0L,
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> true,
                        (Long _) -> vc
                ).buffer().get()
        );
        TestCase.assertEquals(expected, resp);
        TestCase.assertEquals(
                OperationResponse.constructWrongId(),
                BasicsFileControllerStaticMethods.readIdGroup(
                        0L,
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> false,
                        (Long _) -> vc
                )
        );
    }

    @Test
    public void testReadGroup() {
        int size = 100;
        var set = new HashSet<GroupName>(size);
        for (int i = 0; i < size; i++) {
            var name = GroupNameFactory.getGroupNameByString(Integer.toHexString(i).toUpperCase() + "M0").get();
            set.add(name);
        }
        var expected = "{\"groups\":[" + set.stream()
                .sorted()
                .map(GroupName::toJSONElement)
                .collect(
                        Collectors.joining(", ")
                ) + "]}";
        var ret = BasicsFileControllerStaticMethods.readGroups(
                (String _) -> {},
                set::stream
        );
        TestCase.assertEquals(expected, String.valueOf(ret.buffer().get()));
    }

    @Test
    public void testFreeIDs() {
        int size = 100;
        var random = new Random(System.currentTimeMillis());
        var ids = new ArrayList<Pair<Long,Long>>(size);
        var expected = new StringBuilder("{\"diapason\":[");
        for (int i = 0; i < size; i++) {
            Long id1 = Math.abs(random.nextLong()) % 100_000L;
            Long id2 = Math.abs(random.nextLong()) % 100_000L + 100_000L;
            ids.add(Pair.of(id1, id2));
            expected.append("[" + Long.toHexString(id1) + "," + Long.toHexString(id2) + "],");
        }
        expected.deleteCharAt(expected.lastIndexOf(","));
        expected.append("]}");
        var actual = BasicsFileControllerStaticMethods.readFreeIds(
                0L,
                (String _) -> {},
                (String _) -> {},
                (Long _) -> true,
                (Long _) -> ids.stream()
                        .map((a) -> new Long[]{a.getLeft(), a.getRight()})
                        .toArray(Long[][]::new)
        );
        TestCase.assertEquals(expected.toString(), String.valueOf(actual.buffer().get()));
    }

    @Test
    public void testUpdateBuf() {
        var buffer = "FUCK";
        Long id = 0L;
        var vc = VirtualCatalogueFactory.constructTest("02M60");
        vc.touch(id);
        BasicsFileControllerStaticMethods.updateBuf(
                id,
                buffer.toCharArray(),
                (String _) -> {},
                (String _) -> {},
                (Long _) -> true,
                (Long _) -> vc
        );
        TestCase.assertEquals(buffer, String.valueOf(vc.readDirectly(id, buffer.length()).get()));
    }

    @Test
    public void testUpdateAppendBuf() {
        var init = "OH MY ";
        var buffer = "FUCK";
        Long id = 0L;
        var vc = VirtualCatalogueFactory.constructTest("01M60");
        vc.touch(id);
        vc.writeDirectly(id, init.toCharArray());
        BasicsFileControllerStaticMethods.updateAppendBuf(
                id,
                buffer.toCharArray(),
                (String _) -> {},
                (String _) -> {},
                (Long _) -> true,
                (Long _) -> vc
        );
        var ret = vc.readDirectly(id, init.length() + buffer.length()).get();
        TestCase.assertEquals(
                (init + buffer),
                String.valueOf(vc.readDirectly(id, init.length() + buffer.length()).get())
        );
    }

    @Test
    public void testDelete() {
        Long id = 0L;
        var vc = VirtualCatalogueFactory.constructTest("08M60");
        vc.touch(id);
        TestCase.assertEquals(
                OperationResponse.constructSuccess(),
                BasicsFileControllerStaticMethods.delete(
                        id,
                        (String _) -> {},
                        (String _) -> {},
                        (Long a) -> a.equals(id),
                        (Long _) -> vc
                )
        );
        TestCase.assertFalse(vc.exists(id));
        TestCase.assertEquals(
                OperationResponse.constructWrongId(),
                BasicsFileControllerStaticMethods.delete(
                        id,
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> false,
                        (Long _) -> vc
                )
        );
    }

    @Test
    public void testSoftDelete() {
        TestCase.assertEquals(
                OperationResponse.constructSuccess(),
                BasicsFileControllerStaticMethods.deleteCatalogueSoft(
                    0L,
                    (String _) -> {},
                    (Long _) -> {}
                )
        );
    }


    @Test
    public void testHardDelete() {
        Long id = 0L;
        var vc = VirtualCatalogueFactory.constructTest("09M60");
        vc.touch(id);
        TestCase.assertEquals(
                OperationResponse.constructSuccess(),
                BasicsFileControllerStaticMethods.deleteCatalogueHard(
                        0L,
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> true,
                        (Long _) -> vc,
                        (Long _) -> {}
                )
        );
        TestCase.assertEquals(
                OperationResponse.constructWrongId(),
                BasicsFileControllerStaticMethods.deleteCatalogueHard(
                        0L,
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> false,
                        (Long _) -> vc,
                        (Long _) -> {}
                )
        );
        TestCase.assertEquals(
                OperationResponse.constructSomethingGoesWrong(),
                BasicsFileControllerStaticMethods.deleteCatalogueHard(
                        0L,
                        (String _) -> {},
                        (String _) -> {},
                        (Long _) -> true,
                        (Long _) -> vc,
                        (Long _) -> {}
                )
        );
    }
}
